home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Utilities / Compression / Unix Compression / unshar v.1.5 / unshar source / unshar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-19  |  17.3 KB  |  773 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        unshar.c
  3.  
  4.     Contains:    unshar for MPW that's good enough for
  5.                 comp.sources.unix archives
  6.  
  7.     Written by:    sw
  8.                 Network Analysis Ltd
  9.                 178 Wainbody Ave South
  10.                 Coventry CV3 6BX
  11.                 UK
  12.     Phone:        +44 203 419996
  13.     E-mail:        sw@network-analysis-ltd.co.uk
  14.     
  15.     Copyright:    Public domain
  16.  
  17.     Change History (most recent first):
  18.  
  19.     <7>             19/5/91    sw        Remove tests for "if"s and make less sensitive to
  20.                                     variations in shar file formats. Also stop
  21.                                     looking for #! /bin/sh; any comment line will do.
  22.                                     Merge MPW and Think C vers into 1 src file.
  23.     <6>             16/5/91    sw        Handle shar files in sumex archives.
  24.     <5>              3/5/91    sw        Previous mod didn't get the last char of the
  25.                                     filename.
  26.     <4>              3/5/91    sw        Cope with shar files that do not quote the
  27.                                     filename in the "if test -f" line.
  28.     <3>              3/2/91    sw        Pick up terminating string from "sed" or "cat"
  29.                                     command line.
  30.     <2>              5/7/90      sw        Reconvert to MPW tool
  31.     <1>              ??????    aw        Original by Amanda Walker, Intercon
  32.  
  33.     To Do:
  34. */
  35. #ifdef    MPW
  36. #include <Types.h>
  37. #include <StdDef.h>
  38. #include <Files.h>
  39. #include <CursorCtl.h>
  40. #include <StdLib.h>
  41. #endif    MPW
  42. #include <errno.h>
  43. #include <stdio.h>
  44. #include <String.h>
  45. #ifndef NIL
  46. #define NIL    (0L)
  47. #endif
  48.  
  49. /* Strings used in error messages */
  50. #ifdef    MPW
  51. #define    CPSTR        c2pstr
  52. #define PCSTR        p2cstr
  53. #else
  54. #define CPSTR        CtoPstr
  55. #define PCSTR        PtoCstr
  56. #endif
  57.  
  58. #ifndef EOF
  59. #define EOF    (-1L)
  60. #endif
  61.  
  62. #ifndef    MPW
  63. /*    for Think C
  64. */
  65.  
  66. /* if using new Think C headers, uncomment the following line, otherwise
  67.    use the line after that. Only one of the following pair of lines should be used
  68. */
  69. #define    LOWMEM_LONG(lowMemVar)    (*((long *)lowMemVar))        /* use this if new-style TC headers */
  70. /*
  71. #define LOWMEM_LONG(lowMemVar)    (lowMemVar)                    /* use this if old-style TC headers */
  72.  
  73. #define DIRECTORY(pb)    (((pb).dirInfo.ioFlAttrib & 0x10) == 0x10)
  74. #define    getDir    11            /* buttons in the dialogue box */
  75. #define    getCurDir    12
  76. #define    GD_PROMPT    13
  77.  
  78. typedef enum
  79. {
  80.     infoDlgRes = 1000,
  81.     aboutAlrtRes,            /* About... alert resource number */
  82.     abortRes,
  83.     gdDlgRes,
  84.     typeDlgRes,
  85.     errorAlertRes,
  86.     dupFNAlertRes
  87. };
  88.  
  89.  
  90. typedef enum                /* File menu item numbers */
  91. {
  92.     extract = 1,
  93.     close,
  94.     quit
  95. };
  96.  
  97.  
  98. typedef enum                 /* Edit menu item numbers */
  99. {
  100.     undo = 1,
  101.     /* --- */
  102.     cut = 3,
  103.     copy,
  104.     paste,
  105.     clear
  106. };
  107.  
  108. typedef enum                /* Option menu item numbers */
  109. {
  110.     forceOpt = 1,
  111.     setCr
  112. };
  113.  
  114. typedef enum                /* dialog item numbers */
  115. {
  116.     okB = 1,
  117.     crText,
  118.     cancelB
  119. };
  120.  
  121. typedef enum
  122. {
  123.     continueB = 1,
  124.     quitB,
  125.     messageItem
  126. };
  127.  
  128. MenuHandle    fileM, editM, optM;
  129. short        dirVRefNum = 0;
  130. char        *progname;
  131. short        appFileCount,
  132.             whatToDo;
  133. DialogPtr    infoDlgPtr, typeDlgPtr;
  134.  
  135. #endif                                /* Think C declarations */
  136.  
  137. Boolean force =     false;          /* force overwriting existing files */
  138. OSType    fdCreator =    'MPS ';            /* Finder Creator */
  139. OSType    fdType =    'TEXT';            /* Finder Type */
  140.  
  141. void ErrMsg (char *p1, char *p2);
  142.                                     /* for display errors */
  143. void ConvertFName (char *unixfilename, char *mpwfilename);
  144.                                     /* for converting Unix->Mac filenames */
  145. void unshar(char *s);                /* the guts of the program */
  146.  
  147. #ifndef    MPW
  148. /*    Prototypes for Think C standalone version */
  149. void SetDText(DialogPtr dlog, int item, Str255 str);
  150. void GetDText(DialogPtr dlog, int item, StringPtr str);
  151. void GetCreator(void);
  152. void DoFileMenu(int item);
  153. void DoEditMenu(int item);
  154. void DoOptMenu(int item);
  155. void DoAbout(void);
  156. pascal short DirSelHook(int item, DialogPtr theDialog);
  157. pascal Boolean DirFilterProc(CInfoPBPtr pb);
  158. long GetDir(char *text);
  159. void GetNextFile(SFReply *fInfoPtr);
  160. void Extract(void);
  161.  
  162.  
  163. void SetDText(DialogPtr dlog, int item, Str255 str)
  164. {
  165. Handle    itemHandle;
  166. int        itemType;
  167. Rect    itemRect;
  168.  
  169.     GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
  170.     SetIText (itemHandle, str);
  171. }
  172.  
  173. /* Dialog handler */
  174.  
  175. void GetDText(DialogPtr dlog, int item, StringPtr str)
  176. {
  177. Handle    itemHandle;
  178. int        itemType;
  179. Rect    itemRect;
  180.  
  181.     GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
  182.     GetIText (itemHandle, str);
  183. }
  184.  
  185.  
  186. void GetCreator(void)
  187. {
  188.     int        itemHit;
  189.     char    creator[5];
  190.  
  191.     typeDlgPtr = GetNewDialog (typeDlgRes, NIL, (WindowPtr) -1L);
  192.     BlockMove(&fdCreator, creator+1, 4);
  193.     creator[0] = '\004';
  194.     SetDText(typeDlgPtr, crText, (StringPtr)creator);
  195.     SelectWindow(typeDlgPtr);
  196.     ShowWindow(typeDlgPtr);
  197.     DrawDialog(typeDlgPtr);
  198.     ModalDialog(NIL, &itemHit);
  199.     if (itemHit == okB) {
  200.         GetDText (typeDlgPtr, crText,(StringPtr) &creator);
  201.         BlockMove(creator+1, &fdCreator, 4);
  202.     }
  203.     DisposDialog(typeDlgPtr);
  204. }
  205.  
  206.  
  207. /*
  208.     File menu handler
  209. */
  210.  
  211. void DoFileMenu(int item)
  212. {
  213. WindowPeek    wPeek;
  214.  
  215.     switch (item)
  216.     {
  217.         case extract:
  218.             Extract();
  219.             break;
  220.         case close:
  221.             if ((wPeek = (WindowPeek) FrontWindow ()) != NIL)
  222.             {
  223.                 if (wPeek->windowKind < 0)
  224.                     CloseDeskAcc (wPeek->windowKind);
  225.             }
  226.             break;
  227.         case quit:
  228.             SkelWhoa ();
  229.             break;
  230.     }
  231. }
  232.  
  233.  
  234. void DoEditMenu(int item)
  235. {
  236. DialogPtr    theDialog;
  237.  
  238.     theDialog = (DialogPtr) FrontWindow ();
  239.     if (((WindowPeek) theDialog)->windowKind != dialogKind)
  240.         return;
  241.  
  242.     switch (item)
  243.     {
  244.         case cut:
  245.         {
  246.             DlgCut (theDialog);
  247.             (void) ZeroScrap ();
  248.             (void) TEToScrap ();
  249.             break;
  250.         }
  251.  
  252.         case copy:
  253.         {
  254.             DlgCopy (theDialog);
  255.             (void) ZeroScrap ();
  256.             (void) TEToScrap ();
  257.             break;
  258.         }
  259.  
  260.         case paste:
  261.         {
  262.             (void) TEFromScrap ();
  263.             DlgPaste (theDialog);
  264.             break;
  265.         }
  266.  
  267.         case clear:
  268.         {
  269.             DlgDelete (theDialog);
  270.             break;
  271.         }
  272.     }
  273. }
  274.  
  275. void DoOptMenu(item)
  276. int        item;
  277. {
  278.     switch (item)
  279.     {
  280.         case forceOpt:    force = !force;
  281.                                         CheckItem(optM, forceOpt, force);
  282.                                         break;
  283.          case setCr:        GetCreator();
  284.                                      break;
  285.      }
  286. }
  287.  
  288. /*
  289.     Handle selection of About… item from Apple menu
  290. */
  291.  
  292. void DoAbout(void)
  293. {
  294.     (void) Alert (aboutAlrtRes, NIL);
  295. }
  296.  
  297. Boolean        useCurDir;        /* Set if current dir to be used */
  298.  
  299. /* Filter procs & dialogue hooks to select directories only in SFGet file */
  300. pascal short DirSelHook(int item, DialogPtr theDialog)
  301. {
  302.     if (item == getDir|| item == getCurDir) {
  303.         /* folder selected */
  304.         useCurDir = item == getCurDir;
  305.         item = getOpen;
  306.     }
  307.     return(item);
  308. }
  309.  
  310. pascal Boolean DirFilterProc(CInfoPBPtr pb)
  311. {
  312.     return(!DIRECTORY(*pb));    /* a directory if bit 4 is set */
  313. }
  314. /*
  315.  * GetDir - manage the directory selection dialog
  316.  */
  317. long GetDir(char *text)
  318. {
  319.     char        *routine = "\pGetDir";
  320.     Point        where;
  321.     short        ht, wd;
  322.     SFReply        reply = {0};
  323.     CInfoPBRec    pb;
  324.     DialogPtr    dlgP;
  325.     long        dirDirID=0;        /* Selected directory DirID */
  326.  
  327.     if ((dlgP = GetNewDialog(gdDlgRes, NIL,(WindowPtr) -1)) == NIL) {
  328.         return(TRUE);
  329.     }
  330.     wd = (dlgP->portRect.right)-(dlgP->portRect.left);
  331.     ht = (dlgP->portRect.bottom)-(dlgP->portRect.top);
  332.     /* centre the dialogue box on the screen
  333.        (but how do I know which screen?)
  334.     */
  335.     where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
  336.     where.v = (screenBits.bounds.bottom-screenBits.bounds.top-ht) / 2;
  337.     ParamText((StringPtr)text, (StringPtr)"\p", (StringPtr)"\p", (StringPtr)"\p");
  338.     SFPGetFile (where,
  339.                 (StringPtr)text,
  340.                 (FileFilterProcPtr) DirFilterProc,
  341.                 -1, NIL,
  342.                 (DlgHookProcPtr) DirSelHook,
  343.                 &reply,
  344.                 gdDlgRes, NIL);
  345.     if (reply.good) {
  346.         dirVRefNum = reply.vRefNum;
  347.         if (useCurDir) {
  348.             dirDirID = *((long *)CurDirStore);
  349.         }
  350.         else {
  351.             dirDirID = (long)(reply.fType);
  352.         }
  353.     }
  354.     return(dirDirID);
  355. }
  356.  
  357. void GetNextFile(SFReply *fInfoPtr)
  358. {    AppFile    nextFile;
  359.     static    short    idx=1;
  360.  
  361.     GetAppFiles(idx++, &nextFile);
  362.     fInfoPtr->vRefNum = nextFile.vRefNum;
  363.     fInfoPtr->fType = nextFile.fType;
  364.     fInfoPtr->version = nextFile.versNum;
  365.     BlockMove(nextFile.fName, fInfoPtr->fName, (int)(nextFile.fName[0]+1));
  366.     appFileCount--;
  367. }
  368.  
  369. void Extract(void)
  370. {
  371.     Point        where;
  372.     SFReply        reply;
  373.  
  374.     while (1){
  375.         if (appFileCount > 0) GetNextFile(&reply);
  376.         else {
  377.             /*
  378.              * Use the standard file dialog to select the archive.
  379.              */
  380.             where.h = where.v = 75;
  381.             SFGetFile(where, (StringPtr)"\pSelect shar file", NIL, -1, NIL, NIL, &reply);
  382.             if (!reply.good)
  383.                 return;
  384.         }
  385.     
  386.         /*
  387.          * Remember the VRefNum and Name for OpenArchive.
  388.          * Find out where to put the extracted files.
  389.          */
  390.         (void) SetVol(NIL, reply.vRefNum);
  391.         PtoCstr((char *)reply.fName);
  392.         unshar((char *)reply.fName);
  393.         (void) SetVol(NIL, reply.vRefNum);
  394.     }
  395. }
  396.  
  397. main(int argc, char *argv[])
  398. {
  399.  
  400.     Handle        fTypeH;
  401.     DialogTHndl    dlgH;
  402.     Point        where;
  403.     short        ht, wd;
  404.         
  405.     SkelInit (3, NIL);
  406.     SkelApple ("\pAbout Unshar…", DoAbout);
  407.  
  408.     fileM = NewMenu (1000, (StringPtr)"\pFile");
  409.     AppendMenu (fileM, (StringPtr)"\pExtract/O;Close/K;Quit/Q");
  410.     SkelMenu (fileM, DoFileMenu, NIL, FALSE);
  411.  
  412.     editM = NewMenu (1001, (StringPtr)"\pEdit");
  413.     AppendMenu (editM, (StringPtr)"\p(Undo/Z;(-;Cut/X;Copy/C;Paste/V;Clear");
  414.     SkelMenu (editM, DoEditMenu, NIL, FALSE);
  415.  
  416.     optM = NewMenu (1002, (StringPtr)"\pOptions");
  417.     AppendMenu (optM, (StringPtr)"\pOverwrite existing files;File type...");
  418.     SkelMenu (optM, DoOptMenu, NIL, TRUE);
  419.     
  420.     CountAppFiles (&whatToDo, &appFileCount);
  421.     if ((fTypeH = (char **)GetResource('ftyp', 0)) == NIL) {
  422.         ExitToShell();
  423.     }
  424.     BlockMove(*fTypeH, &fdCreator, 4);
  425.     BlockMove((*fTypeH)+4, &fdType, 4);
  426.     ReleaseResource(fTypeH);
  427.     
  428.     CouldDialog(typeDlgRes);
  429.     CouldDialog(infoDlgRes);
  430.     dlgH = (DialogTHndl)GetResource('DLOG', typeDlgRes);
  431.     wd = ((* dlgH)->boundsRect.right)-((* dlgH)->boundsRect.left);
  432.     /* centre the dialogue box on the screen
  433.        (but how do I know which screen?)
  434.     */
  435.     where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
  436.     (* dlgH)->boundsRect.right += where.h;
  437.     (* dlgH)->boundsRect.left = where.h;
  438.     
  439.     dlgH = (DialogTHndl)GetResource('DLOG', infoDlgRes);
  440.     wd = ((* dlgH)->boundsRect.right)-((* dlgH)->boundsRect.left);
  441.     /* centre the dialogue box on the screen
  442.        (but how do I know which screen?)
  443.     */
  444.     where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
  445.     (* dlgH)->boundsRect.right += where.h;
  446.     (* dlgH)->boundsRect.left = where.h;
  447.  
  448.     /* if launched with a set of files, extract them first before asking
  449.        the user for more
  450.     */
  451.     if (appFileCount > 0)
  452.         Extract();
  453.     SkelMain ();
  454.     SkelClobber ();
  455.     FreeDialog(typeDlgRes);
  456.     FreeDialog(infoDlgRes);
  457. }
  458. #else                                /* MPW main support routines */
  459.  
  460. main(int argc, char *argv[])
  461. {
  462.     char    **filelist;                /* list of files to process */
  463.     int        fileCount = 0;            /* no of files to process */    
  464.  
  465. #ifdef    MPW
  466.     InitCursorCtl(nil);
  467. #endif    MPW
  468.     argc--; argv++;
  469.     if ((filelist = (char **)calloc((size_t)argc, sizeof(Ptr))) == NULL) {
  470.         fprintf(stderr, "### Not enough memory\n");
  471.         exit(-1);
  472.     }
  473.     while (argc) {
  474.         if (argv[0][0] == '-') {
  475.             switch (argv[0][1]) {
  476.             case '\0':
  477.                 filelist[fileCount++] = "-";
  478.                 break;
  479.             case 'c':
  480.                 /* creator is in next arg */
  481.                 argc--;
  482.                 argv++;
  483.                 strncpy((char *)&fdCreator, argv[0], (size_t)4);
  484.                 break;
  485.             case 'f':
  486.                 force = true;
  487.                 break;
  488.             case 't':
  489.                 /* type is in next arg */
  490.                 argc--;
  491.                 argv++;
  492.                 strncpy((char *)&fdType, argv[0], (size_t)4);
  493.                 break;
  494.             default:
  495.                 fprintf(stderr, "### Usage: unshar -f -c creator -t type [files|-]\n");
  496.                 exit(-1);
  497.             }
  498.         }
  499.         else
  500.             filelist[fileCount++] = argv[0];
  501.         argc--; argv++;
  502.     }
  503.     /* at this point all files to process are in filelist */
  504.     for (argc = 0; argc < fileCount; argc++) {
  505.         unshar(filelist[argc]);
  506.     }
  507. }
  508. #endif
  509.  
  510. /*    This part (mostly) common to both MPW and Think C */
  511.  
  512. void ErrMsg (char *p1, char *p2)
  513. {
  514. #ifdef    MPW
  515.     fprintf (stderr, "### %s %s\n", p1+1, p2);
  516. #else
  517.     ParamText((StringPtr)p1, (StringPtr)p2, (StringPtr)"\p", (StringPtr)"\p");
  518.     (void)StopAlert(errorAlertRes, NIL);
  519. #endif
  520. }
  521.  
  522. void ConvertFName (char *unixfilename, char *macfilename)
  523. {
  524.     char    *cp, *tp;
  525.     char    buf[256];
  526.     Boolean    slashSeen = false;
  527.     
  528.     /* make a Mac relative pathname */
  529.     /*    rules of the game:
  530.         'foo' -> foo
  531.         "foo" -> foo
  532.         `foo` -> foo
  533.         ./foo -> foo
  534.         foo/baz -> :foo:baz
  535.         .foo -> _foo
  536.         foo/./baz -> :foo:baz
  537.         /foo/baz -> :foo:baz
  538.         foo:baz -> foo/baz
  539.         
  540.         rules apply recursively
  541.     */
  542.     
  543.     (void) strcpy(macfilename, ":");            /* initialize with a leading colon */
  544.     for (cp = buf, tp = unixfilename; *tp; tp++) {
  545.         switch (*tp) {
  546.             case '\'':
  547.             case '"':
  548.             case '`':    break;                    /* delete these chars */
  549.             case '.':    if (*(tp+1) == '/') {
  550.                             tp++;
  551.                         }
  552.                         else if (cp == buf)
  553.                             *cp++ = '_';        /* replace leading dot with _ */
  554.                         else
  555.                             *cp++ = '.';
  556.                         break;                    /* delete any occurence of ./ */
  557.             case '/':    if (cp != buf)
  558.                             *cp++ = ':';        /* replace / with : */
  559.                         slashSeen = true;
  560.                         break;
  561.             case ':':    *cp++ = '/';            /* replace : with / */
  562.                         break;
  563.             default:    *cp++ = *tp;
  564.                         break;
  565.         }
  566.     }
  567.     *cp = '\0';
  568.     
  569.     if (slashSeen)
  570.         (void) strcat(macfilename, buf);
  571.     else
  572.         (void) strcpy(macfilename, buf);
  573.  
  574. }
  575.  
  576. void unshar(char *s)
  577. {
  578.   char        buffer[BUFSIZ];
  579.   char        *cp;
  580.   FILE        *infp, *outfp;
  581.   char        unixfilename[256], mpwfilename[256];
  582.   char        *tp, *ts, delim;
  583.   char        terminator[30];
  584.   int        tlen;
  585.   int        line;
  586.   long        dirID, dID;
  587.   short        v;
  588.   FInfo        fileInfo;
  589. #ifndef    MPW
  590.   WDPBRec    wdpb;
  591.   char        lineNo[10];
  592. #endif
  593.  
  594. #ifdef    MPW
  595.   if (strcmp(s, "-") == 0) {
  596.       infp = stdin;
  597.     ErrMsg("\pProcessing std input:","");
  598.   }
  599.   else {
  600.       infp = fopen(s, "r");
  601.       if (!infp) {
  602.         ErrMsg("\pCould not open file", s);
  603.         exit(-1);
  604.       }
  605.       else ErrMsg("\pProcessing", s);
  606.   }
  607. #else    /* Think C */
  608.   infp = fopen(s, "r");
  609.   CtoPstr(s);
  610.   if (!infp) {
  611.     ErrMsg("\pCould not open file", s);
  612.     return;
  613.   }
  614. #endif
  615.  
  616.   /* skip over news header lines etc. */
  617.   for (line = 1; cp = fgets(buffer, sizeof(buffer), infp); line++)
  618.     if (buffer[0] == '#' || buffer[0] == ':') break;
  619.     
  620.   if (!cp) {
  621.     ErrMsg("\pCould not locate start of archive in file", s);
  622.     exit(-1);
  623.   }
  624.  
  625. #ifndef    MPW
  626.   /* Think C version needs to ask user to locate target folder */
  627.  
  628.   /*
  629.    * Open the target directory as a base to put everything.
  630.    */
  631.   if ((dirID = GetDir("\pin which to put extracted files")) == 0L)
  632.       return;
  633.   
  634.   dID = dirID;            /* dID may be changed if subfolders are created */
  635.   (void)HSetVol(NIL, dirVRefNum, dirID);
  636.   
  637.   /* now we should be at the start of the shar archive itself */
  638.   infoDlgPtr = NIL;
  639.   infoDlgPtr = GetNewDialog (infoDlgRes, NIL, (WindowPtr)-1L);
  640. #endif
  641.  
  642.   while (cp = fgets(buffer, sizeof(buffer), infp)) {
  643.     line++;
  644. #ifdef    MPW
  645.     SpinCursor(-1);
  646. #endif    MPW
  647.  
  648.     if (buffer[0] == '#' || buffer[0] == ':') continue;    /* comment line */
  649.     if (strncmp(buffer, "exit", 4) == 0) { break; }  /* exit */
  650.  
  651.     /*    there are 2 types of shar files:
  652.         a) the ones that use "cat"
  653.         b) the ones that use "sed"
  654.     */
  655.     if (strncmp(buffer, "sed", 3) == 0 ||
  656.         strncmp(buffer, "cat", 3) == 0) {
  657.           sscanf(buffer, "%*[^>]>%s", unixfilename);
  658.           /* make Mac relative pathname */
  659.           ConvertFName(unixfilename, mpwfilename);
  660.  
  661.           /* work out the terminating string */
  662.           sscanf(buffer, "%*[^<]<<%s", terminator);
  663.           tp = terminator;
  664.           tlen = strlen(terminator);
  665.           
  666.           while (*tp == ' ') tp++;        /* skip whitespace */
  667.           switch (*tp) {
  668.               case '\\':    ts = tp + 1;    /* start of term string */
  669.                             delim = ' ';
  670.                             break;
  671.               case '"':        ts = tp + 1;
  672.                             delim = *tp;
  673.                             break;
  674.               case '\'':    ts = tp + 1;
  675.                             delim = *tp;
  676.                             break;
  677.               default:        ts = tp;
  678.                             delim = ' ';
  679.                             break;                
  680.           }
  681.           do {
  682.               tp++;
  683.           } while (*tp != '\0' && *tp != delim);
  684.           *tp = '\0';
  685.           tlen = tp - ts;
  686.  
  687.           outfp = fopen(mpwfilename, "r");
  688.           if (outfp && !force) {
  689.             fclose(outfp);
  690. #ifdef    MPW
  691.             ErrMsg("\pWill not overwrite existing file", mpwfilename);
  692. #else
  693.              CtoPstr(mpwfilename);
  694.             ParamText((StringPtr)"\pWill not overwrite existing file",
  695.                       (StringPtr)mpwfilename, (StringPtr)"\p", (StringPtr)"\p");
  696.             if (NoteAlert(dupFNAlertRes, NIL) == quitB) break;
  697. #endif
  698.             while (strncmp(buffer, ts, tlen) != 0) {  /* skip to terminating string */
  699.               fgets(buffer, sizeof(buffer), infp);
  700.               line++;
  701.             }
  702.           } else {
  703.  
  704.             if (outfp) fclose(outfp);
  705. #ifdef MPW
  706.             fprintf(stderr, "  Open \"%s\"\n", mpwfilename);
  707. #else
  708.             CtoPstr(mpwfilename);
  709.             Create((StringPtr)mpwfilename, dID, fdCreator, fdType);
  710.             ParamText((StringPtr)mpwfilename,
  711.                       (StringPtr)"\p", (StringPtr)"\p", (StringPtr)"\p");
  712.             SelectWindow(infoDlgPtr);
  713.             ShowWindow(infoDlgPtr);
  714.             DrawDialog(infoDlgPtr);         
  715.             PtoCstr(mpwfilename);
  716. #endif
  717.             outfp = fopen(mpwfilename, "w");
  718.             
  719.             if (strncmp(buffer, "sed", 3) == 0) {
  720.                 fgets(buffer, sizeof(buffer), infp);
  721.                 do {
  722.                   fputs(buffer+1, outfp);
  723.                   fgets(buffer, sizeof(buffer), infp);
  724.                   line++;
  725. #ifdef    MPW
  726.                   SpinCursor(1);
  727. #endif    MPW
  728.                 } while (strncmp(buffer, ts, tlen) != 0);
  729.             }
  730.             else {
  731.                 /* copy everything up to terminating string to output file */
  732.                 fgets(buffer, sizeof(buffer), infp);
  733.                 while (strncmp(buffer, ts, tlen) != 0) {
  734.                     fputs(buffer, outfp);
  735.                     fgets(buffer, sizeof(buffer), infp);
  736.                     line++;
  737. #ifdef    MPW
  738.                     SpinCursor(1);
  739. #endif    MPW
  740.                 }
  741.             }
  742.             fclose(outfp);
  743. #ifndef    MPW
  744.             HideWindow((WindowPtr)infoDlgPtr);
  745. #endif
  746.             /* set file type and creator */
  747.             CPSTR(mpwfilename);
  748.             GetFInfo((StringPtr)mpwfilename,0,&fileInfo);
  749.             fileInfo.fdType = fdType;
  750.             fileInfo.fdCreator = fdCreator;
  751.             SetFInfo((StringPtr)mpwfilename, 0, &fileInfo);
  752.             PCSTR(mpwfilename);
  753.           }
  754.       } else if (strncmp(buffer, "if test ! -d", 12) == 0 ||
  755.                    strncmp(buffer, "if `test ! -d", 13) == 0) {
  756.         /* testing to see if a directory is there */
  757.         if (sscanf(buffer, "if test ! -d '%s'", unixfilename) == 1 ||
  758.             sscanf(buffer, "if test ! -d %s", unixfilename) == 1 ||
  759.             sscanf(buffer, "if `test ! -d %s`", unixfilename) == 1) {
  760.           /* make Mac relative pathname */
  761.           ConvertFName(unixfilename, mpwfilename);
  762.             
  763.           /* I wish MPW C had mkdir(), but at least we don't have to do parameter blocks */
  764.           CPSTR(unixfilename);
  765.           CPSTR(mpwfilename);
  766.           HGetVol((StringPtr)unixfilename, &v, &dirID);
  767.           DirCreate(v, dirID, (StringPtr)mpwfilename, &dID);
  768.         }
  769.     }
  770.   }
  771.   fclose(infp);
  772. }
  773.